home *** CD-ROM | disk | FTP | other *** search
/ Amiga Developer CD 2.1 / Amiga Developer CD v2.1.iso / Reference / Amiga_Mail_Vol2 / Archives / Plain / ma90 / libraryiii-11.txt < prev    next >
Encoding:
Text File  |  1990-05-18  |  29.8 KB  |  1,077 lines

  1. (c)  Copyright 1990 Commodore-Amiga, Inc.   All rights reserved.
  2. The information contained herein is subject to change without notice,
  3. and  is provided "as is" without warranty of any kind, either express
  4. or implied.   The entire risk as to the use of this information is
  5. assumed by the user.
  6.  
  7.  
  8. Creating Your Own Library
  9.  
  10.  
  11. Michael Sinz
  12.  
  13. On the Amiga, programmers can easily add their own function
  14. libraries to the system.  The LIBS: directory of the Workbench
  15. disk contains .library files.  These are disk-loadable function
  16. libraries that are linked into the system only when needed by an
  17. application.  For instance, the IEEE math functions comprise a
  18. disk-loadable library.  
  19.  
  20. Disk-loadable libraries are sometimes called shared-code
  21. libraries since their functions are callable from multiple
  22. programs at once.  This means that all functions in the library
  23. must be reentrant.  Also, any functions that the library calls
  24. have to be reentrant too.   For instance, sprintf() from the
  25. standard C link library is not reentrant. and should not be
  26. called from a disk-loadable library.  In addition to being
  27. reentrant, the library has to correctly employ semaphores to
  28. protect any shared data structures.  
  29.  
  30. This article presents a working example of a disk-loadable
  31. library and shows you how to create your own using Lattice C. 
  32. You may also want to refer to the assembly-language example
  33. library in the Includes and Autodocs Manual (Addison-Wesley, ISBN
  34. 0-201-18177-0, page G-13).  For the basics on how libraries work
  35. on the Amiga, refer to the ROM Kernel Manual: Libraries and
  36. Devices (Addison-Wesley, ISBN 0-201-18187-8, page 229).
  37.  
  38. Selecting Your Library Functions
  39.  
  40. The first step in creating your own library is to select the
  41. functions you will use for entry points and come up with the
  42. parameters the functions will need.  The parameters must be data
  43. items that can fit into a processor register.  That is, you can
  44. not pass a structure, but you can pass a pointer to it.  Our
  45. example library will consist of exactly three functions, Cube(),
  46. Count(), and FunStuff().  The parameters to the three routines
  47. are:
  48.  
  49.        long = Cube (long num);
  50.        d0           d0
  51.  
  52.        long = Count (void);
  53.        d0
  54.  
  55.        void FunStuff(long num,char *text);
  56.                      d0       a0
  57.  
  58.  
  59. Selecting Registers for Each Function Argument
  60.  
  61. In this example, the Cube() function has one argument, the
  62. Count() function has none, and the FunStuff() function has two. 
  63. Here are the rules for selecting registers to use for the
  64. function arguments:
  65.  
  66. o Don't select registers arbitrarily.  A thoughtful selection    
  67.     makes a real difference in the performance of your library.
  68. o Select registers starting at the low numbers.  (d0, d1, d2...)
  69. o Select registers that best describe what the argument is.  If  
  70.     the argument is a data item select a d register.  If the    
  71.     argument is an address, select an a register.
  72. o You must not select a4, a6 or a7 since these are special cases. 
  73.     If you do the system will crash.
  74.  
  75.  
  76. Make Your Function Prototypes File
  77.  
  78. For this example, the prototypes would be:
  79.     long __saveds __asm LIBCube(register __d0 long num);
  80.     long __saveds __asm LIBCount(void);
  81.     void __saveds __asm LIBFunStuff(register __d0 long num, 
  82.                                      register __a0 char *text);
  83.  
  84. Note the compiler directives __saveds, __asm and register __d0. 
  85. The __saveds directive is used to define a subroutine that loads
  86. up the global base pointer into a4 upon entry.  That way the
  87. small-data model can be used for compilation.  The __asm
  88. directive is used to define a subroutine which takes its
  89. parameters in a specific register.  The register __d0 directive
  90. actually tells which register to use for the parameter.
  91.  
  92.  
  93. From the Prototypes, Make a .fd File
  94.  
  95. The .fd file is used to make #pragma statements for the compiler
  96. such that programs can call your library.  It also is used by the
  97. linker (BLink) to make the library table.  For this example the
  98. .fd file would be:
  99.  
  100.     ##base _ExampleLibBase
  101.     ##bias 30
  102.     Cube(num)(A0)
  103.     Count()
  104.     FunStuff(num,text)(D0/A0)
  105.     ##end
  106.  
  107. The first line describes the library base name.  The second line
  108. is the standard table bias needed for a library.  The next three
  109. lines give the function call names and the registers they use (if
  110. any).
  111.  
  112.  
  113. Set Up the Custom Init and Expunge Code For Your Library
  114.  
  115. The Init code should initialize anything special that may be
  116. needed by the library.  This could include opening other
  117. libraries that your library might be calling or initializing data
  118. structures it may need.  In this example, there is a global
  119. semaphore that is initialized during the Init routine and a few
  120. other libraries that are opened.  
  121.  
  122. Expunge frees anything allocated by the Init code.  Our example
  123. library closes the libraries that  it uses.  Refer to the file
  124. Examplelib_Custom.c to see how this is done.
  125.  
  126. Note that these are custom routines specific to the library. 
  127. These are called by the generic initialize and expunge entries
  128. which are part of every library.  The generic initialization,
  129. open, close, and expunge routines are listed in the libinit.c
  130. file.
  131.  
  132.  
  133. Write Your Library Functions
  134.  
  135. Of course our library functions will need some code to execute. 
  136. The code for this example is listed in the file Examplelib.c.
  137.  
  138.  
  139. Put Revision Information Into Header Files
  140.  
  141. The library revision number is important for keeping track of
  142. versions and helps  insure future compatibility for the library. 
  143. For this example, the revision information  appears in the header
  144. files Examplelib_rev.h and Examplelib_rev.i.
  145.  
  146.  
  147. Compile the Library
  148.  
  149. Once you have all the required files for a library, compile it. 
  150. Then copy the resulting library file to the LIBS: directory. 
  151. (Note that you can put the library anywhere you want so long as
  152. you give the complete path name to the library in the
  153. OpenLibrary() call.)
  154.  
  155. The lmk file for our example library is listed below.  Keep in
  156. mind  that BLink uses the name of the binary file that you
  157. compile as the name of the library.  For this example, the name
  158. is Examplelib.library.
  159.  
  160. Test the Library
  161.  
  162. You should test and debug the library as a normal C linked
  163. library before compiling it into the final disk-loadable form. 
  164. Once the functions are debugged, create the .library version and
  165. do the final testing.  A test program for the example library
  166. called libtest.c is listed below.
  167.  
  168. When you are making changes to the disk-loadable version of a
  169. library, you will need to cause a system expunge in order to
  170. flush the old version of the library from the system so that the
  171. new one can be tried. To do this you would first make sure all
  172. programs have closed the old library, place the new version of
  173. the library in the LIBS: directory, and finally, cause a system
  174. expunge.  This can be done with the avail -flush command from the
  175. CLI or with the Workbench debug-menu option, flushlibs.  Note
  176. that you must use loadwb -debug in you startup script to get the
  177. Workbench debug-menu.
  178.  
  179. The Example Library Files
  180.  
  181. Altogether there are 13 files in this example library.
  182.  
  183. 1) examplelib.c
  184. This is the place where the library function call code is.  This
  185. can be more than one module, but for this example is just one.
  186.  
  187. 2) examplelib.h
  188. Header file for ExampleLib.c that is shared with
  189. examplelib_custom.c in defining any and all global data.  Note
  190. that global data that is modified needs to be protected via
  191. semaphores.
  192.  
  193. 3) examplelib_custom.c
  194. This is the custom library initialization and expunge code.  The
  195. routines in here are used to set up library-specific items upon
  196. loading of the library and to clean up when an expunge occurs. 
  197. The routines here are called by the standard library
  198. initialization and expunge entries of the library
  199. in the libinit.c file.
  200.  
  201. 4) examplelib_custom.h
  202. This is the prototype header for the examplelib_custom.c
  203. initialization and expunge code.
  204.  
  205. 5) examplelib_lib.fd
  206. This is the .fd file (function definition) for the library.  It
  207. defines the function names, their position in the library vector
  208. table, and the registers that their parameters are passed in.  It
  209. also is used to generate the #pragmas in the examplelib_pragma.h
  210. file and to tell the linker how
  211. to build the library itself.
  212.  
  213.  
  214. 6) examplelib_proto.h
  215. These are ANSI style prototypes for the library functions.
  216.  
  217. 7) examplelib_rev.h
  218. This header file contains the C-language definitions of the
  219. library version.
  220.  
  221. 8) examplelib_rev.i
  222. This is the assembly-language definitions of the library version.
  223.  
  224. 9) libent.a
  225. This is the Resident structure (sometimes referred to as a
  226. RomTag) which is required to be in the first hunk of libraries or
  227. other system-objects. It  identifies the object and tells the
  228. system how to initialize it (i.e. the address of the
  229. initialization code).  For more on the Resident structure, refer
  230. to the ROM Kernel Manual: Libraries and Devices, page 234, or see
  231. the exec/resident.h and .i files in the Includes and Autodocs
  232. Manual.
  233.  
  234. 10) endtag.a
  235. This is just a label that is linked into the end of the file so
  236. that the RomTag can point to the end of the RomTag hunk.
  237.  
  238. 11) libinit.c
  239. These are the library initialization, expunge, open, and close
  240. routines required in all libraries.  In general, this file will
  241. remain the same regardless of changes you might make to the
  242. library.  The initialization and expunge routines here will call
  243. the custom library initialization routines in the
  244. examplelib_custom.c file.  Any special setup you might need would
  245. be done in that file.
  246.  
  247. 12) libtest.c
  248. Example code to call the library routines.  This just tests the
  249. library calls and shows that they work.
  250.  
  251. 13) lmkfile
  252. This is the  makefile rules for the Lattice LMK program.  This
  253. will produce all of the files needed.  To run the lmkfile and
  254. compile the library, type lmk at the CLI.  You must be in the
  255. directory containing all the library files when you give the
  256. command.
  257.  
  258.  
  259.  
  260.  
  261. Important Compilation Notes
  262.  
  263. To make this library compile correctly you will need to modify
  264. one of the files that came with Lattice C.  The file
  265. INCLUDE:proto/exec.h needs to have the #pragma syscall changed to
  266. #pragma libcall SysBase. This needs to be done to all of the
  267. #pragmas in the exec.h file.
  268.  
  269. For example, you would change:
  270.  
  271.     #pragma syscall AllocMem c6 1002
  272.  
  273. to this:
  274.  
  275.     #pragma libcall SysBase AllocMem c6 1002
  276.  
  277. This change tells the compiler to load ExecBase not from
  278. AbsExecBase but from the local SysBase which was initialized at
  279. the start of the code.   This change is required in order to make
  280. the -ml (make library) option of Lattice work correctly.  It also
  281. reduces the amount of access to MEMF_CHIP type of memory since
  282. AbsExecBase (location 4) will no longer be referenced.  This can
  283. make for a speed improvement if SysBase is in MEMF_FAST memory
  284. and you are doing complex graphics with lots of video-DMA; the
  285. processor won't be competing with the graphics chips for access
  286. to chip RAM.
  287.  
  288. Since we are using SysBase instead of AbsExecBase, the following
  289. line must be added to the
  290. INCLUDE:proto/exec.h file:
  291.  
  292.     extern struct ExecBase *SysBase;
  293.  
  294. Anywhere near the start of the file is fine.  A complete listing
  295. of all 13 modules in the example library is given on the
  296. following pages.
  297.  
  298.  
  299.  
  300.  
  301. /*
  302.  *    1) examplelib.c - example shared library to be made by blink 5.04
  303.  *
  304.  * These are the actual library functions...
  305.  */
  306.  
  307. #include <exec/types.h>
  308. #include <exec/libraries.h>
  309. #include <intuition/intuition.h>
  310. #include <proto/exec.h>
  311. #include <proto/intuition.h>
  312. #include <proto/graphics.h>
  313.  
  314. #include <dos.h>
  315.  
  316. /*
  317.  * This is the file that contains the few global data value
  318.  * definitions...
  319.  */
  320. #include "examplelib.h"
  321.  
  322. /*
  323.  * Define the place where the library base is...
  324.  */
  325. #define ExampleLibBase (getreg(REG_A6))
  326.  
  327. /*
  328.  * Prototypes for the library functions
  329.  */
  330. #include "examplelib_proto.h"
  331. #include "examplelib_pragma.h"
  332.  
  333. /*
  334.  * We will define the prefix for our library vectors to be
  335.  * _LIB so that the Cube call will call the real _LIBCube
  336.  * vector in sted of calling the function directly.
  337.  *
  338.  * This is important as if the call to the function directly
  339.  * was used, it would be impossible to "SetFunction" the function
  340.  * and have ALL users of that function use the new one.
  341.  *
  342.  * Since C automatically adds the _ in front of labels,
  343.  * we just need to have LIB defined...
  344.  */
  345.  
  346. long __saveds __asm LIBCube(register __d0 long num);
  347. long __saveds __asm LIBCount(void);
  348. void __saveds __asm LIBFunStuff(register __d0 long num,register __a0 char *name);
  349.  
  350. /*  Blink will plunk globals into the library base: */
  351. long Invocations = 314;
  352.  
  353. /* This helps seed the random number generator */
  354. static ULONG RandomValue = (long)&RandomValue;
  355.  
  356. /*
  357.  * First external routine
  358.  */
  359. long __saveds __asm LIBCube(register __d0 long num)
  360. {
  361.     return(num*num*num);
  362. }
  363.  
  364. /*
  365.  * Second external routine that does not take arguments...
  366.  */
  367. long __saveds __asm LIBCount(void)
  368. {
  369. long trivialtest;
  370.  
  371.     /*
  372.      * Note that we call the LIBCube() function via Cube()
  373.      * This makes this call go through the standard library
  374.      * vectors.
  375.      */
  376.     trivialtest = Cube(5);
  377.  
  378.     /*
  379.      * Since we will be modifying public data, we need
  380.      * to protect it.  That is what the MyDataSemaphore is.
  381.      * Before using any public data that could be modified,
  382.      * we grab the semaphore.
  383.      *
  384.      * Note that using the semaphore method is much better
  385.      * than Forbid()/Permit() for overall system performance.
  386.      * However, you can not use the Semaphore if you need to
  387.      * call the function from within a Forbid()...  (Since
  388.      * ObtainSemaphore() could block...)
  389.      */
  390.     ObtainSemaphore(&MyDataSemaphore);
  391.     Invocations++;
  392.  
  393.     /*
  394.      * Note that we will copy the value into another "stack" variable
  395.      * as after we release the semaphore the value may change.
  396.      */
  397.     trivialtest=Invocations;
  398.     ReleaseSemaphore(&MyDataSemaphore);
  399.  
  400.     return(trivialtest);
  401. }
  402.  
  403. /*
  404.  * This routine is internal and uses the RandomValue global seed.
  405.  */
  406. ULONG RandomNext(void)
  407. {
  408. ULONG NewRandom;
  409.  
  410.     ObtainSemaphore(&MyDataSemaphore);
  411.     NewRandom=RandomValue;
  412.     RandomValue=(((NewRandom<<13)^(NewRandom>>11))+NewRandom)>>1;
  413.     ReleaseSemaphore(&MyDataSemaphore);
  414.     return(NewRandom);
  415. }
  416.  
  417. /*
  418.  * This is an internal routine that just draws some stuff in the
  419.  * window's RastPort.
  420.  */
  421. void DrawStuff(struct Window *win)
  422. {
  423. short x;
  424. short y;
  425.  
  426.     x=win->Width-win->BorderLeft-win->BorderRight-1;
  427.     y=win->Height-win->BorderTop-win->BorderBottom-1;
  428.  
  429.     SetDrMd(win->RPort,JAM1);
  430.     SetAPen(win->RPort,RandomNext()%4);
  431.     Move(win->RPort,(RandomNext() % x) + win->BorderLeft,
  432.             (RandomNext() % y) + win->BorderTop);
  433.     Draw(win->RPort,(RandomNext() % x) + win->BorderLeft,
  434.             (RandomNext() % y) + win->BorderTop);
  435. }
  436.  
  437. /*
  438.  * Third external call that does some fun stuff...
  439.  */
  440. void __saveds __asm LIBFunStuff(register __d0 long num,register __a0 char *name)
  441. {
  442. register short flag=TRUE;
  443. register struct Window *w;
  444. register struct IntuiMessage *msg;
  445.          struct NewWindow nw;
  446.  
  447.     nw.LeftEdge=num;
  448.     nw.TopEdge=num;
  449.     nw.Width=486-num;
  450.     nw.Height=143-num;
  451.     nw.DetailPen=0;
  452.     nw.BlockPen=1;
  453.     nw.IDCMPFlags=CLOSEWINDOW|INTUITICKS;
  454.     nw.Flags=WINDOWDRAG|WINDOWDEPTH|WINDOWCLOSE|NOCAREREFRESH|ACTIVATE;
  455.     nw.Title=name;
  456.     nw.FirstGadget=NULL;
  457.     nw.MinWidth=nw.Width;
  458.     nw.MinHeight=nw.Height;
  459.     nw.MaxWidth=nw.Width;
  460.     nw.MaxHeight=nw.Height;
  461.     nw.Type=WBENCHSCREEN;
  462.  
  463.     if (w=OpenWindow(&nw))
  464.     {
  465.         while(flag)
  466.         {
  467.             DrawStuff(w);
  468.             WaitPort(w->UserPort);
  469.             if (msg=(struct IntuiMessage *)GetMsg(w->UserPort))
  470.             {
  471.                 if (msg->Class==CLOSEWINDOW) flag=FALSE;
  472.                 ReplyMsg((struct Message *)msg);
  473.             }
  474.         }
  475.         CloseWindow(w);
  476.     }
  477. }
  478. -------------------------------------------------------------------------
  479. /*
  480.  *    2) examplelib.h - example shared library to be made by blink 5.04
  481.  *
  482.  * These are the library globals...
  483.  */
  484.  
  485. #include <exec/types.h>
  486. #include <exec/semaphores.h>
  487.  
  488. /*
  489.  * This is the semaphore that we will use to protect the data
  490.  */
  491. extern struct SignalSemaphore MyDataSemaphore;
  492.  
  493. /*
  494.  * This is a global data variable.
  495.  */
  496. extern long Invocations;
  497.  
  498.  
  499.  
  500. ------------------------------------------------------------------------------
  501. /*
  502.  * 3) examplelib_custom.c
  503.  *
  504.  * Custom library initialization goes here...
  505.  *
  506.  * This contains the custom LibInit and LibExpunge routines for
  507.  * the library we are making...
  508.  */
  509.  
  510. #include <exec/types.h>
  511. #include <exec/alerts.h>
  512. #include <proto/exec.h>
  513.  
  514. #include <dos.h>
  515.  
  516. /*
  517.  * Include the prototypes for the custom init and expunge vectors...
  518.  */
  519. #include "examplelib_custom.h"
  520.  
  521. /*
  522.  * Global data definition
  523.  */
  524. #include "examplelib.h"
  525.  
  526. /*
  527.  * These are the libraries that we call from within our library.
  528.  */
  529. struct ExecBase *SysBase = NULL;
  530. struct GfxBase *GfxBase = NULL;
  531. struct IntuitionBase *IntuitionBase = NULL;
  532.  
  533. struct SignalSemaphore MyDataSemaphore;
  534.  
  535. /*
  536.  * This is the custom LibInit code.
  537.  *
  538.  * This is where the library specific initialization code should be.
  539.  *
  540.  *  *** NOTE ***  Note that it is best to use a little stack
  541.  *                as possible as you are being called from some
  542.  *                other process's context.
  543.  *
  544.  *                Also note that the *FIRST* thing that must happen
  545.  *                in this routine is to set up SysBase as shown...
  546.  */
  547. BOOL __saveds __asm CustomLibInit(register __a6 struct Library *libbase)
  548. {
  549.     /* Get SysBase set up... this MUST happen *FIRST* */
  550.     SysBase=(struct ExecBase *) (* ((ULONG *)4) );
  551.  
  552.     /* Initialize our semaphore */
  553.     InitSemaphore(&MyDataSemaphore);
  554.  
  555.     /*  Get the libraries we rely on */
  556.     GfxBase=(struct GfxBase *)OpenLibrary("graphics.library",33L);
  557.     if (!GfxBase)
  558.     {
  559.         Alert(AG_OpenLib|AO_GraphicsLib,(APTR)libbase);
  560.         /* !!! Bryce says nobody frees libbase ! */
  561.         return ( FALSE );
  562.     }
  563.  
  564.     IntuitionBase=(struct IntuitionBase *)OpenLibrary("intuition.library",33L);
  565.     if (!IntuitionBase)
  566.     {
  567.         Alert(AG_OpenLib|AO_Intuition,(APTR)libbase);
  568.         /* !!! Bryce says nobody frees libbase! */
  569.         /* !!! I'm not closing GfxBase, unless expunge is called! */
  570.         return ( FALSE );
  571.     }
  572.     return ( TRUE );
  573. }
  574.  
  575. /*
  576.  * This is the custom LibExpunge code.
  577.  *
  578.  * This is where the library specific expunge code should be placed.
  579.  *
  580.  *  *** NOTE ***  This routine *MUST* *NEVER* *BREAK* *FORBID*
  581.  *                That is, it must not do *ANYTHING* that could
  582.  *                cause a Wait() to happen...
  583.  *
  584.  *                Also note that it is best to use a little stack
  585.  *                as possible as you are being called from some
  586.  *                other process's context.
  587.  */
  588. void __saveds __asm CustomLibExpunge(register __a6 struct Library *libbase)
  589. {
  590.     /* Close the libraries it uses: */
  591.     if (IntuitionBase)
  592.     {
  593.         CloseLibrary((struct Library *)IntuitionBase);
  594.         IntuitionBase=NULL;
  595.     }
  596.     if (GfxBase)
  597.     {
  598.         CloseLibrary((struct Library *)GfxBase);
  599.         GfxBase=NULL;
  600.     }
  601. }
  602.  
  603. ----------------------------------------------------------------------------
  604. /* 4) examplelib_custom.h 
  605.  *
  606.  * The prototypes for the custom library init and expunge
  607.  */
  608. BOOL __saveds __asm CustomLibInit(register __a6 struct Library *libbase);
  609. void __saveds __asm CustomLibExpunge(register __a6 struct Library *libbase);
  610.  
  611. ----------------------------------------------------------------------------
  612.  
  613. /* 5) example _lib.fd            */
  614.  
  615. ##base _ExampleLibBase
  616. ##bias 30
  617. Cube(num)(D0)
  618. Count()
  619. FunStuff(num,name)(D0/A0)
  620. ##end
  621.  
  622. -------------------------------------------------------------------------------
  623. /*
  624.  *  6) examplelib_proto.h - Prototypes for the example library
  625.  */
  626. long Cube(long);
  627. long Count(void);
  628. void FunStuff(long,char *);
  629.  
  630. -----------------------------------------------------------------------------
  631. /*
  632.  * 7) examplelib_rev.h
  633.  */
  634.  
  635. #define    VERSION        36
  636. #define    REVISION    1
  637. #define    DATE    "27 Nov 1989"
  638. #define    VERS    "examplelib 36.1"
  639. #define    VSTRING    "examplelib 36.1 (27 Nov 1989)\n\r"
  640.  
  641. -----------------------------------------------------------------------------
  642. /*
  643.  * 8) examplelib_rev.i
  644.  */
  645.  
  646. VERSION        EQU    36
  647. REVISION    EQU    1
  648. DATE    MACRO
  649.         dc.b    '27 Nov 1989'
  650.     ENDM
  651. VERS    MACRO
  652.         dc.b    'examplelib 36.1'
  653.     ENDM
  654. VSTRING    MACRO
  655.         dc.b    'examplelib 36.1 (27 Nov 1989)',13,10,0
  656.     ENDM
  657.  
  658.  
  659. -----------------------------------------------------------------------------
  660. ***
  661. *
  662. * 9) libent.asm - Modified Lattice Library Resident (RomTag) Structure
  663. *
  664. ***
  665.     include    'exec/types.i'
  666.     include    'exec/resident.i'
  667.     include    'exec/nodes.i'
  668.     include    'exec/libraries.i'
  669. ***
  670. *
  671. * The following include is used to store the library version and name
  672. * as follows:
  673. *
  674. * VERSION        EQU    36
  675. * REVISION        EQU    1
  676. * DATE        MACRO
  677. *            dc.b    '27 Nov 1989'
  678. *        ENDM
  679. * VERS        MACRO
  680. *            dc.b    'examplelib 36.1'
  681. *        ENDM
  682. * VSTRING    MACRO
  683. *            dc.b    'examplelib 36.1 (27 Nov 1989)',13,10,0
  684. *        ENDM
  685. *
  686. ***
  687.     include 'examplelib_rev.i'
  688. ***
  689. *
  690. * Library init priority.  For user (NON-ROM) libraries, should be 0
  691. *
  692. ***
  693. PRI    equ    0
  694. ***
  695. *
  696. * Define some the external references...
  697. *
  698. ***
  699.     xref    __LibName
  700.     xref    RESLEN
  701.     xref    _BSSBAS        ; linker defined base of BSS
  702.     xref    _BSSLEN        ; linker defined length of BSS
  703.     xref    _LibFuncTab
  704.     xref    __LibInitTab
  705.     xref    endtag
  706.     xref    _LibInit
  707.     xdef    __LibRomTag
  708.     xdef    __VerString
  709. ***
  710. *
  711. * This is the first hunk and is where the RomTag is needed...
  712. *
  713. ***
  714.     SECTION    text,CODE    ; romtag must be in first hunk
  715. ***
  716. *
  717. * We need to make sure that if some user tries to execute this
  718. * file as an executable that we return an error...
  719. *
  720. ***
  721.     moveq    #20,d0
  722.     rts
  723. ***
  724. *
  725. * Place the version string into the tag.  This makes the
  726. * version displayable.  It also makes it possible to "TYPE"
  727. * the library file to find out the version...
  728. *
  729. ***
  730. __VerString:    VSTRING
  731. ***
  732. *
  733. * The RomTag that is needed for a library
  734. *
  735. ***
  736.     cnop    0,2        ; We need to word-align the RomTag
  737. __LibRomTag:
  738.     dc.w    RTC_MATCHWORD
  739.     dc.l    __LibRomTag
  740.     dc.l    endtag
  741.     dc.b    RTF_AUTOINIT
  742.     dc.b    VERSION
  743.     dc.b    NT_LIBRARY
  744.     dc.b    PRI
  745.     dc.l    __LibName
  746.     dc.l    __VerString
  747.     dc.l    __LibInitTab
  748. ***
  749. *
  750. * Start of the merged data area that the linker puts
  751. * into the library structure for the global data.
  752. *
  753. ***
  754.     section    __MERGED,data
  755.     xdef    __Libmergeddata
  756. __Libmergeddata    dc.l    0
  757.     end
  758.  
  759.  
  760. ---------------------------------------------------------------------------
  761. *
  762. *   10) endtag.a  -       For RomTag EndSkip
  763. *
  764.         section text,data       ; so it is dead-last (data hunk)
  765.  
  766.         XDEF    endtag
  767. endtag:
  768.  
  769.         END
  770.  
  771. ---------------------------------------------------------------------------
  772. /*
  773.  * 11) libinit.c
  774.  *
  775.  * This is the standard library init...
  776.  *
  777.  * It calls the custom init routines in examplelib_custom.c
  778.  * The routines in this file should not be changed.
  779.  *
  780.  * Portions of this code were generated from Lattice examples...
  781.  */
  782. #include <exec/types.h>
  783. #include <exec/nodes.h>
  784. #include <exec/resident.h>
  785. #include <exec/libraries.h>
  786. #include <libraries/dos.h>
  787. #include <proto/exec.h>
  788. #include <proto/dos.h>
  789. #include <string.h>
  790.  
  791. /*
  792.  * This includes the revision information
  793.  */
  794. #include "examplelib_rev.h"
  795.  
  796. /*
  797.  * Include the custom init and expunge headers...
  798.  *
  799.  * The MUST be of the type:
  800.  * BOOL __asm __saveds CustomLibInit(register __a6 struct Library *libbase);
  801.  * void __asm __saveds CustomLibExpunge(register __a6 struct Library *libbase);
  802.  *
  803.  */
  804. #include "examplelib_custom.h"
  805.  
  806. struct MyLibrary
  807. {
  808.     struct  Library ml_Lib;
  809.     ULONG   ml_SegList;
  810.     ULONG   ml_Flags;
  811.     APTR    ml_ExecBase;        /* pointer to exec base */
  812.     LONG    ml_Data;                /* Global data */
  813. };
  814.  
  815. typedef LONG (*PFL)();   /* pointer to function returning 32-bit int        */
  816.  
  817. /* library initialization table, used for AUTOINIT libraries                */
  818. struct InitTable
  819. {
  820.     ULONG   *it_DataSize;       /* library data space size         */
  821.     PFL     *it_FuncTable;      /* table of entry points           */
  822.     APTR    it_DataInit;        /* table of data initializers      */
  823.     PFL     it_InitFunc;        /* initialization function to run  */
  824. };
  825.  
  826. /* my function table (Generated by Blink) */
  827. extern PFL _LibFuncTab[];
  828.  
  829. extern char __far RESLEN;
  830. extern long __far NEWDATAL;    /* Generated by BLINK */
  831.  
  832. #define DATAWORDS ((long)&NEWDATAL)
  833.  
  834. /* We need to define this for the following table */
  835. ULONG __asm _LibInit(register __a0 APTR seglist,register __d0 struct MyLibrary *libbase);
  836.  
  837. struct InitTable __far _LibInitTab =
  838. {
  839.     (long *)(&RESLEN+sizeof(struct MyLibrary)),
  840.     _LibFuncTab,
  841.     NULL,            /* will initialize my own data */
  842.     _LibInit,
  843. };
  844.  
  845. /* Need this to determine start of MERGED DATA */
  846. extern long far _Libmergeddata;
  847.  
  848. /* Supplied by BLink */
  849. extern char __far _LibName[];
  850.  
  851. /* Supplied as part of our libent.a */
  852. extern char __far _VerString[];
  853.  
  854. /*
  855.  * The following #define is to give the EXEC call #pragmas
  856.  * (which were changed to "libcall SysBase" to use the
  857.  * absolute location known also as AbsExecBase.  This is
  858.  * needed during the base level expunge call...
  859.  */
  860. #define SysBase (*((ULONG *)4))
  861.  
  862. /*
  863.  * This function is called when the library is first loaded.
  864.  * It does the library structure initialization and calls
  865.  * the custom library initialization routine which should
  866.  * setup any custom library stuff and open any other libraries
  867.  * that will be needed.
  868.  *
  869.  * Note that this routine can not change as the setup must
  870.  * happen in this order.
  871.  */
  872. ULONG __asm _LibInit(register __a0 APTR seglist,register __d0 struct MyLibrary *libbase)
  873. {
  874. long *sdata, *reloc;
  875. char *ddata;
  876. long nrelocs;
  877.  
  878.     libbase->ml_SegList = (ULONG) seglist;
  879.  
  880.     /* init. library structure (since I don't do automatic data init.) */
  881.     libbase->ml_Lib.lib_Node.ln_Type = NT_LIBRARY;
  882.     libbase->ml_Lib.lib_Node.ln_Name =  _LibName;
  883.     libbase->ml_Lib.lib_Flags = LIBF_SUMUSED | LIBF_CHANGED;
  884.     libbase->ml_Lib.lib_Version = VERSION;
  885.     libbase->ml_Lib.lib_Revision = REVISION;
  886.     libbase->ml_Lib.lib_IdString = (APTR) _VerString;
  887.  
  888.     /* The +4 is a wasted long word, where _Libmergeddata is. */
  889.     ddata = (char *)&libbase->ml_Data+4;
  890.     sdata = (long *)&_Libmergeddata;
  891.     memcpy(ddata, (char *)sdata, DATAWORDS*4);
  892.  
  893.     sdata = sdata + DATAWORDS;
  894.     nrelocs = *sdata++;
  895.     while (nrelocs > 0)
  896.     {
  897.         reloc = (long *)((long)ddata + *sdata++);
  898.         *reloc += (long)ddata;
  899.         nrelocs--;
  900.     }
  901.  
  902.     if (CustomLibInit((struct Library *)libbase)) return((ULONG)libbase);
  903.     else return(NULL);
  904. }
  905.  
  906. /*
  907.  * This is the entry point that is called when the system
  908.  * wishes that the library free itself.  The library should
  909.  * only free itself if there are no outstanding open libraries.
  910.  * This routine calls the custom expunge routine where any
  911.  * custom resources that need to be freed are.
  912.  *
  913.  *  *** NOTE ***  This routine *MUST* *NEVER* *BREAK* *FORBID*
  914.  *                That is, it must not do *ANYTHING* that could
  915.  *                cause a Wait() to happen...
  916.  *
  917.  *                Also note that it is best to use a little stack
  918.  *                as possible as you are being called from some
  919.  *                other process's context.
  920.  */
  921. ULONG __saveds __asm _LibExpunge( register __a6 struct MyLibrary *libbase )
  922. {
  923. ULONG seglist = 0;
  924. LONG  libsize;
  925.  
  926.     libbase->ml_Lib.lib_Flags |= LIBF_DELEXP;
  927.     if ( libbase->ml_Lib.lib_OpenCnt == 0 )
  928.     {
  929.         CustomLibExpunge((struct Library *)libbase);
  930.  
  931.         /* really expunge: remove libbase and freemem */
  932.  
  933.         seglist = libbase->ml_SegList;
  934.         Remove( (struct Node *) libbase);
  935.  
  936.         libsize = libbase->ml_Lib.lib_NegSize + libbase->ml_Lib.lib_PosSize;
  937.         FreeMem( (char *) libbase - libbase->ml_Lib.lib_NegSize,(LONG) libsize );
  938.     }
  939.  
  940.     /* return NULL or real seglist */
  941.     return ( (ULONG) seglist );
  942. }
  943.  
  944. /*
  945.  * This is the entry point that is called when the library is
  946.  * opened by an application.  It mainly changes the OpenCount
  947.  * and the delayed expunge flags...
  948.  */
  949. LONG __asm _LibOpen(register __a6 struct MyLibrary *libbase)
  950. {
  951.     /* mark us as having another customer */
  952.     libbase->ml_Lib.lib_OpenCnt++;
  953.  
  954.     /* clear delayed expunges (standard procedure) */
  955.     libbase->ml_Lib.lib_Flags &= ~LIBF_DELEXP;
  956.  
  957.     return((LONG)libbase);
  958. }
  959.  
  960. /*
  961.  * This is the entry point that is called when the library is
  962.  * closed by an application.  The main use here is to change the
  963.  * open count and to check for delayed expunge calls...
  964.  */
  965. ULONG __asm _LibClose( register __a6 struct MyLibrary *libbase )
  966. {
  967. ULONG retval = 0;
  968.  
  969.     if (( --libbase->ml_Lib.lib_OpenCnt == 0 ) &&
  970.                     ( libbase->ml_Lib.lib_Flags & LIBF_DELEXP ))
  971.     {
  972.         /*
  973.          * no more people have me open,
  974.          * and I have a delayed expunge pending
  975.          */
  976.         retval = _LibExpunge( libbase ); /* return segment list */
  977.     }
  978.  
  979.     return (retval);
  980. }
  981.  
  982.  
  983. ---------------------------------------------------------------------------
  984. /*
  985.  *  12) libtest.c
  986.  */
  987.  
  988. #include <proto/exec.h>
  989.  
  990. #include "examplelib_proto.h"
  991. #include "examplelib_pragma.h"
  992.  
  993. struct Library *ExampleLibBase;
  994.  
  995. main()
  996. {
  997.     if (ExampleLibBase = OpenLibrary("examplelib.library", 0L))
  998.     {
  999.         FunStuff(8,"Test with num==8");
  1000.         printf("ExampleLibBase at $%lx\n", ExampleLibBase);
  1001.         printf("Cube 5 = %ld\n", Cube(5));
  1002.         printf("Invocations: %ld\n", Count());
  1003.         FunStuff(12,"Test with num==12");
  1004.         CloseLibrary(ExampleLibBase);
  1005.     }
  1006.     else printf("examplelib.library did not open...\n");
  1007. }
  1008.  
  1009. ------------------------------------------------------------------------
  1010. #
  1011. # 13) lmkfile
  1012. #
  1013. # These are the files for the library.
  1014. # You MUST have a xxx_custom.o for the init/expunge part of the library
  1015. #
  1016. OFILES=examplelib_custom.o examplelib.o
  1017.  
  1018. #
  1019. # These are files needed for the library initialization
  1020. # They should not need to be changed other than the headers
  1021. #
  1022. LIBOFILES=libent.o libinit.o
  1023.  
  1024. #
  1025. # These are the flags needed to compile library routines...
  1026. #
  1027. CFLAGS=-ml -cfist -v -d2
  1028.  
  1029. #
  1030. # The flags needed to assemble the RomTag and EndTag...
  1031. #
  1032. AFLAGS=-iINCLUDE:
  1033.  
  1034. #
  1035. # Default rules...
  1036. #
  1037. .c.o:
  1038.     lc $(CFLAGS) $*
  1039.  
  1040. .a.o:
  1041.     asm $(AFLAGS) $*
  1042.  
  1043. #
  1044. # The whole world...
  1045. #
  1046. all: examplelib_pragma.h examplelib.library libtest
  1047.  
  1048. #
  1049. # This is a little LMK trick for blink...
  1050. #
  1051. # Note that the LIBID is a place to put copyright notices or other
  1052. # information that you may wish to have as part of the library...
  1053. #
  1054. examplelib.library: $(OFILES) $(LIBOFILES) examplelib_lib.fd endtag.o lmkfile
  1055.     blink <with <
  1056. LIBID "Example Library of no real use..."
  1057. LIBPREFIX _LIB
  1058. LIBFD examplelib_lib.fd
  1059. TO examplelib.library
  1060. FROM $(LIBOFILES) $(OFILES)
  1061. LIB lib:lc.lib endtag.o
  1062. SMALLCODE SMALLDATA NODEBUG
  1063. <
  1064.  
  1065. examplelib_pragma.h: examplelib_lib.fd
  1066.     fd2pragma examplelib_lib.fd examplelib_pragma.h
  1067.  
  1068. libtest: libtest.c examplelib_pragma.h
  1069.     lc -L -d2 libtest.c
  1070.  
  1071. libent.o: libent.a examplelib_rev.i
  1072.  
  1073. libinit.o: libinit.c examplelib_rev.h
  1074.  
  1075. endtag.o: endtag.a
  1076.  
  1077.